package edu.bbte;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 *  * Ez az osztaly tartalmaz egy matrix3d "magot" es az ezt korulvevo palasott. 
 * Lenyegeben 3d-s matrixon ertelmezett muveleteket tartalmaz: eltolas forgatas, osszeillesztes, szetvalasztas.
 * 
 * @author      Krisztina Szeles, Robert Rill, Zalan Czirjak 
 * @version     2011.0603
 * @since       1.6
 *
 */

public class MatrixCube {
	public static final int lowerLimit = 3;
	public static final int upperLimit = 6;
	private int size, bound = 1;
	private int [][][] matrix;
	private Matrix3D cube;
	private int pozX, pozY, pozZ; // position of cube part in this big 3D matrice
	/**A vagat szinteje.*/
	private int level;
	/**hany db kicsi kockabol all a vagat.*/
	private int litCubes = 0;
	/**
	 * MatrixCube(meret) - konstruktor. A meret a kockara vonatkozik a belsejeben, 
	 * igy 3*meret lesz a matrix a korbevevessel egyutt. */
	public MatrixCube(int size) {
		if (size < lowerLimit || size > upperLimit)
			System.out.println("LOOK OUT! Size for cube not possible!");
		this.size = size;
		matrix = new int[3*size][3*size][3*size];
		cube = new Matrix3D(size);
		setCubePosition(size, size, size);	//a kockat berakja a nagy 3dmatrix kozepebe
	}
	
	public int getPozX() {
		return pozX;
	}

	public int getPozY() {
		return pozY;
	}

	public int getPozZ() {
		return pozZ;
	}

	/**
	 * sumCube(MatrixCube) - visszateriti ket cube osszeget. Az ellenorzes, 
	 * hogy ne essenek egybe kis kockak es hogy ne logjanak ki megvan.*/
	public boolean sumCube(MatrixCube a) {
		if (!this.canAddCubes(a))
			return false;
		int minI = 3*size, minJ = 3*size, minK = 3*size;
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k){
					setElement(a.getElement(i, j, k) + this.getElement(i, j, k), i, j, k);
					if(this.getElement(i, j, k)!=0){
						if (i<minI) minI = i;
						if (j<minJ) minJ = j;
						if (k<minK) minK = k;
					}
				}
		setCubePosition(minI, minJ, minK);
		return true;
	}
	/**
	 * Kockak osszeillesztesenek vizsgalata.
	 * MatrixCube a - memoriaban talalhato kockankhoz probaljuk hozzaadna*/
	public boolean canAddCubes(MatrixCube a) {
			if (a.getSize() != this.getSize())
				return false;	//ha meretek kulonboznek ... akkor nincs osszeadas		
			int minI = 3*size, minJ = 3*size, minK = 3*size;
			int maxI = 0, maxJ = 0, maxK = 0;
			for (int i = 0; i < 3*size; ++i)
				for (int j = 0; j < 3*size; ++j)
					for (int k = 0; k < 3*size; ++k) {
						if (bound < a.getElement(i, j, k) + this.getElement(i, j, k))
							return false; //ha adott pozicion az eleme osszege nagyobb mint a kuszobszam ... akkor nem jo az osszeadas	
						if (this.getElement(i, j, k) != 0) {
							if (i<minI) minI = i;
							if (i>maxI) maxI = i;
							if (j<minJ) minJ = j;
							if (j>maxJ) maxJ = j;
							if (k<minK) minK = k;
							if (k>maxK) maxK = k;
						}
						if (a.getElement(i, j, k) != 0) {
							if (i<minI) minI = i;
							if (i>maxI) maxI = i;
							if (j<minJ) minJ = j;
							if (j>maxJ) maxJ = j;
							if (k<minK) minK = k;
							if (k>maxK) maxK = k;
						}
					}
					if (maxI - minI >= size) return false;
					if (maxJ - minJ >= size) return false;
					if (maxK - minK >= size) return false;	
		return true;
	}
	/**
	 * differenceCube(MatrixCube) - ket cube kulonbsege. Nemtudom fog-e kelleni, de megvan.*/
	public boolean differenceCube(MatrixCube a) {
		if (a.getSize() != this.getSize()) {
			return false;
		}
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k) {
					int n = this.getElement(i, j, k) - a.getElement(i, j, k);
					if (n < 0)
						return false;
					setElement(n, i, j, k); 
				}
		return true;
	}
	/**
	 * differenceCube(MatrixCube) - ket cube kulonbsege. Nemtudom fog-e kelleni, de megvan.*/
	public boolean differenceLittleCube(MatrixCube a) {
		if (a.getSize() != this.getSize()) {
			return false;
		}
		a.setCubePosition(pozX, pozY, pozZ);
		for (int i = pozX; i < pozX+size; ++i)
			for (int j = pozY; j < pozY+size; ++j)
				for (int k = pozZ; k < pozZ+size; ++k) {
					int n = this.getElement(i, j, k) - a.getElement(i, j, k);
					if (n < 0)
						return false;
					setElement(n, i, j, k); 
				}
		return true;
	}
	/**
	 * printCube() - kiirja a kis kockat reszt a belsejebol a kepernyore. 
	 * Nem muszaj a kozepen legyen, mert mindig megjegyzem a kezdopoziciojat
	 * (a bal, felso sarok elol).*/
	public void printCube() {
		for (int k = pozZ; k < pozZ+size; ++k) {
			for (int i = pozX; i < pozX+size; ++i) {				
				 for (int j = pozY; j < pozY+size; ++j)
					System.out.print(getElement(i,j,k) + " ");
				System.out.println();
			}
			System.out.println();
		}
		System.out.println("---------------");
	}
	
	public int getLitCubes() {
		return litCubes;
	}

	public void setLitCubes() {
		litCubes=0;
		for (int k = pozZ; k < pozZ+size; ++k)
			for (int i = pozX; i < pozX+size; ++i) 				
				 for (int j = pozY; j < pozY+size; ++j)
					 if(matrix[i][j][k]!=0)
						 litCubes++;
	}

	/**
	 * Kockakt egyenloseget ellenorzi,... true ha egyenlok.*/
	public boolean equalsCube(MatrixCube a) {
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k)
					if (this.getElement(i, j, k) != a.getElement(i, j, k))
						return false;
		return true;
	}
	/**
	 * kocka beolvasasa file-bol
	 * String fileName - forrasfile relativ eleresi utvonala*/
	public void readCubeFromFile(String fileName) throws MatrixException {
		try {
			FileReader input = new FileReader(fileName);
			BufferedReader in = new BufferedReader(input);
			String s  = in.readLine();
			int n = Integer.parseInt(s);			//elso sor a kocka merete
			matrix = new int[3*size][3*size][3*size];
			setCubePosition(size, size, size);
			if (cube.getSize() != n)
				throw new MatrixException("Error reading from file: size in file doesn't match with cube size!");
			int i, j;
			for (int k = 0; k < size; ++k) {
				in.readLine();					//ures sor
				for (i = 0; i < size; ++i) {
					s = in.readLine();			
					String [] array = s.split(" ");		//soronkent az elemek <spacec>-el elvalasztva
					if (array.length != size)
						throw new MatrixException("Error reading from file: line length doesn't match with cube size!");
					for (j = 0; j < size; ++j) {
						n = Integer.parseInt(array[j]);
						if (n > bound)				//helytelen adatok beolvasasanak kiszurese
							throw new MatrixException("Error reading from file: element too big in file!");
						cube.setElement(n, i, j, k);
					}
				}
			}
			in.close();
			this.setCube(cube);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**Kocka kiirasa file-ba.
	 * String fileName - forrasfile relativ eleresi utvonala*/
	public void writeCubeToFile(String fileName) {
		try {
			FileWriter output = new FileWriter(fileName);
			BufferedWriter out = new BufferedWriter(output);
			out.write(Integer.toString(size));	//elso sor kocka merete + ures sor
			out.newLine(); out.newLine();
			for (int k = pozZ; k < pozZ+size; ++k) {
				for (int i = pozX; i < pozX+size; ++i) {				
					 for (int j = pozY; j < pozY+size; ++j)
						out.write(Integer.toString(getElement(i,j,k))+" ");	//<space>-el elvalasztva matrix formaban az elemek kiirasa
					out.newLine();
				}
				out.newLine();
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	/**
	 * Kuszobszam ellenorzese a matrixban.
	 */
	public boolean checkBound(int bound) {
		for (int k = 0; k < size; ++k)
			for (int i = 0; i < size; ++i)
				for (int j = 0; j < size; ++j)
					if (bound < getElement(i, j, k) || getElement(i, j, k) < 0)
						return false;
		return true;
	}
	
	public int getElement(int i, int j, int k) {
		return matrix[i][j][k];
	}
	
	public void setElement(int number, int i, int j, int k) {
		matrix[i][j][k] = number;
	}	
	
	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		this.size = size;
	}

	public int[][][] getMatrix() {
		return matrix;
	}

	public void setMatrix(int[][][] matrix) {
		this.matrix = matrix;
	}

	public Matrix3D getCube() {
		Matrix3D a = new Matrix3D(size);
		for (int k = pozZ; k < pozZ+size; ++k)							
			for (int i = pozX; i < pozX+size; ++i)
				for (int j = pozY; j < pozY+size; ++j)
					a.setElement(this.getElement(i, j, k), i-pozX, j-pozY, k-pozZ);
		return a;
	}

	public void setCubePosition(int i, int j, int k) {
		pozX = i;
		pozY = j;
		pozZ = k;
	}
	
	public void setCube(Matrix3D cube) {
		init();
		for (int k = pozZ; k < pozZ+size; ++k)							
			for (int i = pozX; i < pozX+size; ++i)
				for (int j = pozY; j < pozY+size; ++j)
					this.setElement(cube.getElement(i-pozX, j-pozY, k-pozZ), i, j, k);
	}
	
	/**Kockaresz balra tolasa. Technikailag y pozicio csokkentese.*/
	public boolean shiftCubeLeft() {
		if (0 == pozZ)
			return false;
		for (int i = 0; i < 3*size; ++i) 
			for (int k = 0; k < 3*size; ++k)
				if (getElement(i, 0, k) != 0)
					return false;
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY-1, pozZ);	
		a.setCube(this.getCube());
		init();
		setCubePosition(pozX, pozY-1, pozZ);	
		setCube(a.getCube());
		return true;
	}
	/**Kockaresz jobbra tolasa. Technikailag y pozicio novelese.*/
	public boolean shiftCubeRight() {
		if (2*size == pozY)
			return false;
		for (int i = 0; i < 3*size; ++i) 
			for (int k = 0; k < 3*size; ++k)
				if (getElement(i, 3*size-1, k) != 0)
					return false;
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY+1, pozZ);
		a.setCube(this.getCube());
		init();
		setCubePosition(pozX, pozY+1, pozZ);	
		setCube(a.getCube());
		return true;
	}
	/**Kockaresz fel tolasa. Technikailag x pozicio csokkentese.*/
	public boolean shiftCubeUp() {
		if (0 == pozX)
			return false;
		for (int j = 0; j < 3*size; ++j) 
			for (int k = 0; k < 3*size; ++k)
				if (getElement(0, j, k) != 0)
					return false;
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX-1, pozY, pozZ);
		a.setCube(this.getCube());
		init();
		setCubePosition(pozX-1, pozY, pozZ);	
		setCube(a.getCube());
		return true;
	}
	/**Kockaresz le tolasa. Technikailag x pozicio novelese.*/
	public boolean shiftCubeDown() {
		if (2*size == pozX)
			return false;
		for (int j = 0; j < 3*size; ++j) 
			for (int k = 0; k < 3*size; ++k)
				if (getElement(3*size-1, j, k) != 0)
					return false;
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX+1, pozY, pozZ);
		a.setCube(this.getCube());
		init();
		setCubePosition(pozX+1, pozY, pozZ);	
		setCube(a.getCube());
		return true;
	}
	/**Kockaresz elore (tolem) tolasa. Technikailag z pozicio csokkentese.*/
	public boolean shiftCubeForward() {
		if (0 == pozZ)
			return false;
		for (int i = 0; i < 3*size; ++i) 
			for (int j = 0; j < 3*size; ++j)
				if (getElement(i, j, 0) != 0)
					return false;
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY, pozZ-1);
		a.setCube(this.getCube());
		init();
		setCubePosition(pozX, pozY, pozZ-1);	
		setCube(a.getCube());
		return true;
	}
	/**Kockaresz vissza (felem) tolasa. Technikailag z pozicio novelese.*/
	public boolean shiftCubeBack() {
		if (2*size == pozZ)
			return false;
		for (int i = 0; i < 3*size; ++i) 
			for (int j = 0; j < 3*size; ++j)
				if (getElement(i, j, 3*size-1) != 0)
					return false;
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY, pozZ+1);
		a.setCube(this.getCube());
		init();
		setCubePosition(pozX, pozY, pozZ+1);	
		setCube(a.getCube());
		return true;
	}
	
	/** Forgatas a Z tengely menten - elore-hatra tengely*/
	public MatrixCube rotateCubeZ() { 
		try {
			MatrixCube a = new MatrixCube(size);
			FileWriter output = new FileWriter("f.txt");
			BufferedWriter out = new BufferedWriter(output);
			out.write(Integer.toString(size));
			out.newLine();out.newLine();
			for (int k = pozZ; k < pozZ+size; ++k) {
				for (int i = pozX+size-1; i >= pozX; --i) {				
					 for (int j = pozY; j < pozY+size; ++j)
						out.write(Integer.toString(getElement(j, i, k))+" ");
					out.newLine();
				}
				out.newLine();
			}
			out.close();
			
			cube.readCubeFromFile("f.txt");
			a.setCubePosition(pozX, pozY, pozZ);
			a.setCube(cube);
			return a;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MatrixException e) {
			e.printStackTrace();
		}
		return null;
	}

	/** Forgatas az X tengely menten - jobbra-balra tengely
	 */
	public MatrixCube rotateCubeX() {
		try {
			MatrixCube a = new MatrixCube(size);
			FileWriter output = new FileWriter("f.txt");
			BufferedWriter out = new BufferedWriter(output);
			out.write(Integer.toString(size));
			out.newLine();out.newLine();
			for (int i = pozX+size-1; i >= pozX; --i) {				
				for (int k = pozZ; k < pozZ+size; ++k) {
					 for (int j = pozY; j < pozY+size; ++j)
						out.write(Integer.toString(getElement(i, j, k))+" ");
					out.newLine();
				}
				out.newLine();
			}
			out.close();
			
			cube.readCubeFromFile("f.txt");
			a.setCubePosition(pozX, pozY, pozZ);
			a.setCube(cube);
			return a;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MatrixException e) {
			e.printStackTrace();
		}
		return null;
	}
	/** Forgatas az X tengely menten - jobbra-balra tengely
	 */
	public MatrixCube rotateCubeY() {
		try {
			MatrixCube a = new MatrixCube(size);
			FileWriter output = new FileWriter("f.txt");
			BufferedWriter out = new BufferedWriter(output);
			out.write(Integer.toString(size));
			out.newLine();
			out.newLine();
			for (int j = pozY+size-1; j >= pozY; --j) {				
				for (int i = pozX; i < pozX+size; ++i) {
					 for (int k = pozZ; k < pozZ+size; ++k)
						out.write(Integer.toString(getElement(i, j, k))+" ");
					out.newLine();
				}
				out.newLine();
			}
			out.close();
			
			cube.readCubeFromFile("f.txt");
			a.setCubePosition(pozX, pozY, pozZ);
			a.setCube(cube);
			return a;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MatrixException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**Kocka listaban visszateriti a vagat osszes forgatasat.*/
	public MatrixCube [] listOfCubeRotations() {
		MatrixCube [] l = new MatrixCube[24];
		MatrixCube a = this;
		int i, poz = 0;;
		l[0] = a;
		for (i = 0; i < 4; ++i) {
			l[poz] = a;
			++poz;
			a = a.rotateCubeZ();
		}
		a = a.rotateCubeY();
		for (i = 0; i < 4; ++i) {
			l[poz] = a;
			++poz;
			a = a.rotateCubeX();
		}
		a = a.rotateCubeY();
		for (i = 0; i < 4; ++i) {
			l[poz] = a;
			++poz;
			a = a.rotateCubeZ();
		}
		a = a.rotateCubeY();
		for (i = 0; i < 4; ++i) {
			l[poz] = a;
			++poz;
			a = a.rotateCubeX();
		}
		a = a.rotateCubeY();
		a = a.rotateCubeX();
		for (i = 0; i < 4; ++i) {
			l[poz] = a;
			++poz;
			a = a.rotateCubeY();
		}
		a = a.rotateCubeZ();
		a = a.rotateCubeZ();
		for (i = 0; i < 4; ++i) {
			l[poz] = a;
			++poz;
			a = a.rotateCubeY();
		}
		return l;
	}
	
	/**
	 * Kocka lista mely tartalmazza a vagat osszes eltolasat a megadott pozicioszamokkal.
	 * @param left
	 * @param right
	 * @param forward
	 * @param back
	 * @param up
	 * @param down
	 * @return
	 */
	public MatrixCube [] listOfCubeShifts(MatrixCube cube, int up, int down, int left, int right, int forward, int back) {
		int X, Y, Z;
		X = (up + down + 1);
		Y = (left + right + 1);
		Z = (forward + back + 1);
		MatrixCube [] a = new MatrixCube[X*Y*Z];
		MatrixCube b, c, d;
		b = new MatrixCube(this.getSize());
		c = new MatrixCube(this.getSize());
		d = new MatrixCube(this.getSize());
		d.setCube(this.getCube());
		int i,j,k,n=0;
		for (i=0; i<left; ++i) d.shiftCubeLeft();
		for (i=0; i<forward; ++i) d.shiftCubeForward();
		for (i=0; i<up; ++i) d.shiftCubeUp();
		for (k = 0; k < Z; ++k) {
			c.setCubePosition(d.getPozX(), d.getPozY(), d.getPozZ());
			c.setCube(d.getCube());
			for (i = 0; i < X; ++i) {
				b.setCubePosition(c.getPozX(), c.getPozY(), c.getPozZ());
				b.setCube(c.getCube());
				for (j = 0; j < Y; ++j) {	
					if (b.canAddCubes(cube)) {
						a[n] = new MatrixCube(this.getSize());
						a[n].setCubePosition(b.getPozX(), b.getPozY(), b.getPozZ());
						a[n].setCube(b.getCube());
						++n;
					}
					b.shiftCubeRight();
				}
				c.shiftCubeDown();
			}
			d.shiftCubeBack();
		}
		return a;
	}
	
	public void setBound(int bound) {
		this.bound = bound;
	}
	
	public void printAll() {
		for (int k = 0; k < 3*size; ++k) {
			for (int i = 0; i < 3*size; ++i) {				
				 for (int j = 0; j < 3*size; ++j)
					System.out.print(getElement(i,j,k) + " ");
				System.out.println();
			}
			System.out.println();
		}
		System.out.println("---------------------");
	}
	
	/**
	 * Az igazi kocka elemeit modositja.
	 * @param number - milyen erteket kap az adott elem.
	 * @param i - x tengely szerinti koordinata.
	 * @param j - y tengely szerinti koordinata.
	 * @param k - z tengely szerinti koordinata.
	 */
	public void setCubeElement(int number, int i, int j, int k) {
		try{
			matrix[i+pozX][j+pozY][k+pozZ] = number;
			cube.setElement(number, i, j, k);
		}
		catch(ArrayIndexOutOfBoundsException ex)
		{
			System.err.println(ex.getMessage());
		}
	}
	
	/**
	 * Visszateriti a igazi kocka adott elemet.
	 * 
	 * A koordinataknal nem szamit a kockat korulvevo "palast".
	 * @param i - x tengely szerinti koordinata.
	 * @param j - y tengely szerinti koordinata.
	 * @param k - z tengely szerinti koordinata.
	 * @return a kocka eleme (int).
	 */
	public int getCubeElement(int i, int j, int k) {
		return matrix[i+pozX][j+pozY][k+pozZ];
	}
	
	/**
	 * Inicializalja a matrixot 0-al.
	*/
	public void init() {
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k)
					setElement(0,i,j,k);
	}
	/**
	 * MatrixCube tipusu parameterrel inicializalo masolo konstruktor.
	 * @param m - inicializalo kocka
	 */
	public MatrixCube(MatrixCube m){
		if (m.getSize() < lowerLimit || m.getSize() > upperLimit)
			System.out.println("LOOK OUT! Size for cube not possible!");
		this.size = m.getSize();
		
		matrix = new int[3*size][3*size][3*size];
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k)
					setElement(m.getElement(i, j, k),i,j,k);
		
		cube = new Matrix3D(size);
		for (int i = 0; i < size; ++i)
			for (int j = 0; j < size; ++j)
				for (int k = 0; k < size; ++k)
					setCubeElement(m.getElement(i, j, k),i,j,k);
		
		setCubePosition(size, size, size);	//a kockat berakja a nagy 3dmatrix kozepebe
	}
	/**
	 * Megprobalja hozzaadni a matixunkhoz, a parameterkent megadott matrixot.
	 * @param a - hozzaadando matrix
	 * @return true, ha az osszeadas sikeres volt, kulonben false
	 */
	public boolean sumCube2(MatrixCube a){
		if (!this.canAddCubes(a))
			return false;
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k)
					setElement(a.getElement(i, j, k) + this.getElement(i, j, k), i, j, k);
		return true;
	}
	

	/**
	 * Az m MatrixCube lefoglalt elemei helyein, ebben a matrixban a num erteket helyezi el.
	 * @param m - kijelolt helyek, ahol ebben a matrixban majd a num erteke kell legyen.
	 * @param num - ertek amivel lefoglalunk egy kicsi kockat
	 */
	public void fill(MatrixCube m, int num){
		for (int i = 0; i < size; ++i)
			for (int j = 0; j < size; ++j)
				for (int k = 0; k < size; ++k)
					if (m.getCube().getElement(i, j, k)==1)
						this.setCubeElement(num, i, j, k);
	}

	public int getBound() {
		return bound;
	}
	/**
	 * Ellenorzesek nelkuli kockameghatarozas.
	 * @param cube - kocka amivel heyettesitjuk a sajat kockankat
	 */
	private void setCube2(Matrix3D cube) {
		for (int k =0; k < size; ++k)							
			for (int i = 0; i < size; ++i)
				for (int j = 0; j < size; ++j)
					this.setCubeElement(cube.getElement(i, j, k), i, j, k);
	}
	
	/**
	 * Kockaresz fel tolasa. 
	 * Technikailag x tengely szerinti koordintatak csokentese 1-el.
	 * @return true-ha az eltolas sikeres volt, kulonben false.
	 */
	public boolean shiftCubeUp2(){
		//megnezi, hogy lehet-e egyaltalan tolni
		for (int i = 0; i <size; ++i) 
			for (int j = 0; j <size; ++j)
				if (getCubeElement(0, i, j) != 0)
					return false;
		//ha igen akkor ...
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX-1, pozY, pozZ);
		a.setCube2(this.getCube());
		//a.getCube().printMatrix();
		a.setCubePosition(pozX, pozY, pozZ);
		//a.getCube().printMatrix();
		setCube2(a.getCube());
		//this.getCube().printMatrix();
		return true;
	}
	
	/**
	 * Kockaresz le tolasa. 
	 * Technikailag x tengely szerinti koordintatak novelese 1-el.
	 * @return true-ha az eltolas sikeres volt, kulonben false.
	 */
	public boolean shiftCubeDown2(){
		//megnezi, hogy lehet-e egyaltalan tolni
		for (int i = 0; i <size; ++i) 
			for (int j = 0; j <size; ++j)
				if (getCubeElement(size-1, i, j) != 0)
					return false;
		//ha igen akkor ...
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX+1, pozY, pozZ);
		a.setCube2(this.getCube());
		//a.getCube().printMatrix();
		a.setCubePosition(pozX, pozY, pozZ);
		//a.getCube().printMatrix();
		setCube2(a.getCube());
		//this.getCube().printMatrix();
		return true;
	}
	
	/**
	 * Kockaresz balra tolasa. 
	 * Technikailag y tengely szerinti koordintatak csokentese 1-el.
	 * @return true-ha az eltolas sikeres volt, kulonben false.
	 */
	public boolean shiftCubeLeft2(){
		//megnezi, hogy lehet-e egyaltalan tolni
		for (int i = 0; i <size; ++i) 
			for (int j = 0; j <size; ++j)
				if (getCubeElement( i, 0, j) != 0)
					return false;
		//ha igen akkor ...
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY-1, pozZ);
		a.setCube2(this.getCube());
		//a.getCube().printMatrix();
		a.setCubePosition(pozX, pozY, pozZ);
		//a.getCube().printMatrix();
		setCube2(a.getCube());
		//this.getCube().printMatrix();
		return true;
	}
	
	/**
	 * Kockaresz fel tolasa. 
	 * Technikailag y tengely szerinti koordintatak novelese 1-el.
	 * @return true-ha az eltolas sikeres volt, kulonben false.
	 */
	public boolean shiftCubeRight2(){
		//megnezi, hogy lehet-e egyaltalan tolni
		for (int i = 0; i <size; ++i) 
			for (int j = 0; j <size; ++j)
				if (getCubeElement(i, size-1, j ) != 0)
					return false;
		//ha igen akkor ...
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY+1, pozZ);
		a.setCube2(this.getCube());
		//a.getCube().printMatrix();
		a.setCubePosition(pozX, pozY, pozZ);
		//a.getCube().printMatrix();
		setCube2(a.getCube());
		//this.getCube().printMatrix();
		return true;
	}
	
	/**
	 * Kockaresz elore tolasa. 
	 * Technikailag z tengely szerinti koordintatak csokentese 1-el.
	 * @return true-ha az eltolas sikeres volt, kulonben false.
	 */
	public boolean shiftCubeForward2(){
		//megnezi, hogy lehet-e egyaltalan tolni
		for (int i = 0; i <size; ++i) 
			for (int j = 0; j <size; ++j)
				if (getCubeElement(i, j,0) != 0)
					return false;
		//ha igen akkor ...
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY, pozZ-1);
		a.setCube2(this.getCube());
		//a.getCube().printMatrix();
		a.setCubePosition(pozX, pozY, pozZ);
		//a.getCube().printMatrix();
		setCube2(a.getCube());
		//this.getCube().printMatrix();
		return true;
	}
	
	/**
	 * Kockaresz vissza tolasa. 
	 * Technikailag z tengely szerinti koordintatak novelese 1-el.
	 * @return true-ha az eltolas sikeres volt, kulonben false.
	 */
	public boolean shiftCubeBack2(){
		//megnezi, hogy lehet-e egyaltalan tolni
		for (int i = 0; i <size; ++i) 
			for (int j = 0; j <size; ++j)
				if (getCubeElement(i, j,size-1) != 0)
					return false;
		//ha igen akkor ...
		MatrixCube a = new MatrixCube(size);
		a.setCubePosition(pozX, pozY, pozZ+1);
		a.setCube2(this.getCube());
		//a.getCube().printMatrix();
		a.setCubePosition(pozX, pozY, pozZ);
		//a.getCube().printMatrix();
		setCube2(a.getCube());
		//this.getCube().printMatrix();
		return true;
	}

	public void setPozX(int pozX) {
		this.pozX = pozX;
	}

	public void setPozY(int pozY) {
		this.pozY = pozY;
	}

	public void setPozZ(int pozZ) {
		this.pozZ = pozZ;
	}
	
	/**
	 * Az a MatrixCube-ot ugy adjuk a sajatunkhoz, hogy kozben a kialakulando 
	 * kocka poziciojat is beallitjuk.
	 * @param a - matrixunkhoz adando vagat.
	 */
	public void sumCube3(MatrixCube a){
		int minI = 3*size, minJ = 3*size, minK = 3*size;
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k){
					int n = a.getElement(i, j, k) + this.getElement(i, j, k);
					setElement(n, i, j, k);
					if (this.getElement(i, j, k) != 0) {
						if (i<minI) minI = i;
						if (j<minJ) minJ = j;
						if (k<minK) minK = k;
					}
					if (a.getElement(i, j, k) != 0) {
						if (i<minI) minI = i;
						if (j<minJ) minJ = j;
						if (k<minK) minK = k;
					}
				}
		pozX=minI; pozY=minJ; pozZ=minK;
	}
	
	/**
	 * Beallitja a a vagatunk szintjet.
	 * 
	 * Szint alatt itt a kovetkezot ertem: Minden tengely szerint megnezzuk, hogy mekkora
	 * milyen hosszusagban helyezkednek el a lefoglalt elemek. Ezek kozul a minimum a megegyezik
	 * a szint ertekevel.
	 */
	public void setLevel(){
		//System.out.println("Matrix");
		//this.printAll();
		//System.out.println("pozX:"+pozX+" pozY:"+pozY+" pozZ:"+pozZ);
		int minI = 3*size, minJ = 3*size, minK = 3*size;
		int maxI = 0, maxJ = 0, maxK = 0;
		for (int i = 0; i < 3*size; ++i)
			for (int j = 0; j < 3*size; ++j)
				for (int k = 0; k < 3*size; ++k)
					if (this.getElement(i, j, k) != 0) {
						if (i<minI) minI = i;
						if (i>maxI) maxI = i;
						if (j<minJ) minJ = j;
						if (j>maxJ) maxJ = j;
						if (k<minK) minK = k;
						if (k>maxK) maxK = k;
					}
		level = maxI - minI+1;
		if (maxJ - minJ+1  <level) level=maxJ - minJ+1;
		if (maxK - minK+1 <level) level=maxK - minK+1;	
	}
	
	/**
	 * Megnezi, hogy adott pozicion levo elemnek van-e olyan szomszedja amely meg nincs lefoglalva.
	 * @param i - x tengely szerinti koordinata
	 * @param j - y tengely szerinti koordinata
	 * @param k - z tengely szerinti koordinata
	 * @return true, ha kapott le nem foglalt szomszedos elemet, false kulonben.
	 */
	public boolean areThereNoNeighbours(int i, int j, int k){
		if(((i+1)>=0)&&((i+1)<size))
			if(matrix[i+1][j][k]==0)
				return true;
		
		if(((i-1)>=0)&&((i-1)<size))
			if(matrix[i-1][j][k]==0)
				return true;
		
		if(((j+1)>=0)&&((j+1)<size))
			if(matrix[i][j+1][k]==0)
				return true;
		
		if(((j-1)>=0)&&((j-1)<size))
			if(matrix[i][j-1][k]==0)
				return true;
		
		if(((k+1)>=0)&&((k+1)<size))
			if(matrix[i][j][k+1]==0)
				return true;
		
		if(((k-1)>=0)&&((k-1)<size))
			if(matrix[i][j][k-1]==0)
				return true;
		
		return false;
	}

	/*
	public static void main (String[] args){
		MatrixCube piece = new MatrixCube(3);
		piece.setCubeElement(1, 1, 1, 1);
		piece.setCubeElement(1, 1, 2, 1);
		piece.setCubeElement(1, 1, 1, 2);
		if(piece.shiftCubeForward2())
			System.out.print("ok");
		else
			System.out.print("hmm...");
	}
	 */	
}
